Abstract: Patch Extension removes the need for system restarts during each edit-compile-load-test cycle when developing QuicKeys 2(tm) Extensions. It consists of a code resource which temporarily substitutes for your "real" execution routine. It's primary purpose is to open and close your "real" extension located in a separate resource file (located in the system folder) so that your can go through an unlimited number of edit-compile-load-test cycles without rebooting your system each time.
As a general rule, when developing a QuicKey 2 extension, you develop two executable code resources: one to handle the extension's dialog session, and one to actually perform some function. QuicKeys 2 always loads the dialog session resource from the Extension file at each invocation, so one can test a dialog routine, code-compile-link changes, then retest this code without a system restart. However, the execution resource (QkyC) is ONLY loaded (once) during system boot, which means that (for most people) one must restart one's Mac each time one wants to retest a modified extension. This can be real painful if one has lots of inits and/or lots of bugs that need fixing!
Thus Patch Extension. Patch Extension is a partial QuicKeys 2 Extension resource (it consists of QkyC, STR#, and copyright resources) which provides a mechanism for edit-compile-load-test cycles without requiring a restart of your Mac. Now, you can hack away at developing extensions without rebooting each time!
Here's a detailed explanation of how to use it. First, you need to have the "shell" of a working extension, tested enough to know that both the dialog and execution resources load and do something without crashing the system. Make a copy of this (but not in the Extensions folder!) in case you mess something up. Replace the QkyC -14347 resource in your extension in the Extensions folder with the one from Patch Extension, also copying the STR# -14348 resource along with it. Use Resorcerer(tm) (which I really like!) or ResEdit(tm) and open your extension. [Note that when I use QkyC alone in the following text, I'm referring to QkyC -14347, the execution resource.]
Look at (and perhaps edit) the four strings in the STR# -14348 resource. The first string (index 1) is the filename that Patch Extension looks for in the System Folder containing the booted System File. The index 2 string is the OSType in that file which will be loaded and executed by the Patch Extension resource (I'm told that some debuggers want code resources to be of type CODE), and index 3 is that resource's number. Index 4 is a special lRefCon value which is used by your QkyC resource to direct Patch Extension to purge the current loaded QkyC (or STR# -14348 Index 2) resource. Detailed instructions and operation follow (I use ThinkC, so MPW users will have to adjust accordingly).
1) Replace your current QkyC -14347 resource with the Patch Extension QkyC resource.
2) Copy in the STR# -14348 to your extension as well. Create a file in your System Folder called "Test Extension" (or use another name and change the STR# -14348 index 1 to reflect this.
3) You can reboot your Mac now if you want. Patch Extension reads in the STR# when it gets the initX call, but doesn't try to read in your execution routine at this time. After boot, it will attempt to read in your execution routine every time a QuicKey activates it until it succeeds, and will call your QuicKey execution routine with an "initX" (with the file specified in the above mentioned STR# -14348 Index 1 still open, so a GetResource will work, just like it would if you were called by QuicKeys itself at boot). [Note that the GetResource does NOT get resources from the "real" extension in the Extension folder, so sicn and other resources must be duplicated in the "Test Extension" file, as needed for your GetResource calls.]
4) Recompile your QkyC code resource. Merge this resource into the "Test Extension" file (along with any other needed resources) in the System Folder.
Your ExecuteQueue structure (along with your code) is patched into the linked list of QuicKey structures while your extension is actively running. Otherwise, Patch Extension maintains a copy of the data in your ExecuteQueue structure, but unlocks the handle containing your code. Patch Extension always sets the pMyQueue->lRefCon = 0 prior to calling your doExecute routine with the initX selection value. The gist of all this is that unless you do REALLY clever tricks involving changing the ExecuteQueue links, you won't notice any difference in environments. Also, you can get periodic calls (by setting the correct flag) - aborts should work, but since I haven't used that feature I can't say for sure that they'll work.
5) Provide some type of flag mechanism (e.g., a checkbox or an out-of-bounds value in a text field that can act as a "flag" to Patch Extension telling it that you want to purge the current QkyC resource. You MUST purge the current resource before you can merge in another QkyC in the "Test Extension" file, and before Patch Extension will reload it. For instance, I have a checkbox, normally invisible, that says "Purge" in my QuicKeys dialog. My current User Interface code enables and shows this checkbox (since I'm still developing it - when I'm done I'll just not enable it). When my execution routine sees a QuicKey with this flag set true, it sets pMyQueue->lRefCon to -1 (the default purge value) and returns, indication to Patch Extension that it should purge the current QkyC resource. The next QuicKey to come along will result in Patch Extension reloading the QkyC from the "Test Extension" file.
6) Activate your QuicKeys Extension. Test it out. When you're through testing, generate a purge QuicKey. You can then merge new code into the "Test Extension" file and test anew.
7) When (if) you ever get done with your extension, don't forget to merge your Extension QkyC -14347 (did you change the name from QkyC to CODE? if so, change it back) into your "real" extension in the Extensions folder, move any resources added to the real file, and remove the STR# -14348 resource.
8) This sounds like a lot of work! However, modifying and testing your code three of four times without rebooting will convince you of its value. For instance, I'm developing a QuicKey for use with ThinkC, and I test the feature within ThinkC while editing my doExecute routine.
Notes:
a) If you use MacsBug, TMON, or The Debugger you'll get a DebugStr error message if Patch Extension can't find your file, or the resource within it, as directed by the STR# from your extension.
b) Patch Extension loads the QkyC code resource into the system heap, so you may want to use HeapTool or HeapFixer to allocate more system heap space (if your extension code takes up lots of memory). Patch Extension only locks the resource during execution (to be system friendly) so don't assume that the absolute addresses of variables stay constant from invocation to invocation.
c) I'm told that some debuggers won't disassemble arbitrary resources - thus, you may want to change the resource type from QkyC to "CODE" (STR# -14348 Index 2).
Whew, if you got this far, you must be anxious to stop reading and start coding! If you find it helps your out, please send me e-mail at the address below. If not, please send me e-mail at the address below, telling me what the problem is.
David Hoerl
Internet: dfh@garage.att.com
AppleLink: dfh@garage.att.com@INTERNET#
D I S C L A I M E R
This software and accompanying instructions for use are provided "as is" without warranty of any kind. Further, David Hoerl, does not warrant, guarantee, or make any representation regarding the use of the software or accompanying instructions in terms of correctness, accuracy, currentness, or otherwise.
(c) Copyright David Hoerl 1991. Permission is granted to make and distribute copies of this software, provided this disclaimer and copyright notice are preserved on all copies. The software may not, however, be sold or distributed for profit, or included with other software which is sold or distributed for profit, without the permission of the author.
All trademarks referenced are the service mark, trademark, or registered trademark of their respective manufacturer.